#include "job.h"
#include "mem_alloc.h"
#include "dlist.h"

#include <assert.h>
#include <time.h>

#ifdef _WIN32
#else
#include <unistd.h>
#include <pthread.h>
#endif

struct job
{
    struct job * next;
    struct job * prev;

    struct job * g_next;
    struct job * g_prev;

    JM * jm;

    time_t timeout;
    void * data;
};

struct job_manager
{
    job * job_list;
    void * user_data;
};

static job * g_job_list = 0;

int jm_init(JM * jm) 
{
    jm->job_list = 0;
    return 0;
}

JM * jm_create(void * user_data)
{
    JM * jm = GET_OBJECT(JM);
    if (jm_init(jm) != 0) {
        RELEASE_OBJECT(JM, jm);
        jm = 0;
    } else {
        jm->user_data = user_data;
    }
    return jm;
}

void * jm_user_data(JM * jm)
{
    return jm->user_data;
}

void jm_destory(JM * jm)
{
    RELEASE_OBJECT(JM, jm);
}

job * jm_push(JM * jm, void * data, time_t timeout)
{
	job * j;

    if (jm == 0) {
        return 0;
    }

    j = GET_OBJECT(job);
    j->data = data;
    j->timeout = timeout;
    j->jm = jm;

    if (jm) {
        dlist_insert_tail(jm->job_list, j);
    }

    if (g_job_list == 0 ||
        j->timeout <= g_job_list->timeout) {
        dlist_insert_head_x(g_job_list, j, g_prev, g_next);
    } else {
		job * next;
        job * prev = g_job_list->g_prev;
        while (j->timeout <= prev->timeout) {
            prev = prev->g_prev;
        }

        next = prev->g_next;

        j->g_next = next;
        j->g_prev = prev;

        next->g_prev = j;
        prev->g_next = j;
    }
    return j; 
}

void * job_data(job * j, time_t * timeout)
{
    if (j == 0) {
        return 0;
    }
    if (timeout) *timeout = j->timeout;
    return j->data;
}

void * jm_pop(JM * jm, time_t * timeout)
{
    job * j= jm_get(jm);
    void * data = 0;
    if (j) {
        data = j->data;
        if (timeout) *timeout = j->timeout;
        jm_remove(j);
    }
    return data;
}

job * jm_get(JM * jm)
{
    if (jm == 0) {
        return 0;
    }
    return jm->job_list;
}

void  jm_remove(job * j)
{
    if (j) {
        if (j->jm && j->next && j->prev) {
            dlist_remove(j->jm->job_list, j);
        }

        if (g_job_list && j->g_prev && j->g_next) {
            dlist_remove_x(g_job_list, j, g_prev, g_next);
        }
        RELEASE_OBJECT(job, j);
    }
}

job * jm_get_timeout(time_t now, JM ** jm)
{
    job * j;
	if (now == 0) {
        now = time(0);
    }

    j = g_job_list;
    if (j && j->timeout < now) {
        if (jm) *jm = j->jm;
        return j;
    }
    return 0;
}
